#ifndef SEMANTICNODEEXPRESSION_H_
#define SEMANTICNODEEXPRESSION_H_

#include "SemanticNode.h"
#include "SemanticNodeInstanceOf.h"
#include "SemanticNodeCreateArray.h"
#include "SemanticNodeConstructObject.h"
#include "SemanticNodeCast.h"
#include "SemanticNodeVariableName.h"
#include "SemanticNodeMethodStatement.h"
#include "ValueType.h"
#include "../main_container.h"
#include <map>

extern MainContainer *CompilerData;

struct AtomicStatement {
	enum Action {
		LogicOr,
		LogicXor,
		LogicAnd,
		LogicNot,
		CompareLT,
		CompareGT,
		CompareLEQ,
		CompareGEQ,
		CompareEQ,
		CompareNEQ,
		Add,
		Deduct,
		Multiply,
		Divide,
		Modulus,
		Power
	};
	Action action;
	std::string resultBuffer;
	std::string op1ID;
	std::string op2ID;
};

class SemanticNodeExpression : public SemanticNode, public ValueType {
private:
	enum Semantics {
		SNCast,
		SNConstructObject,
		SNCreateArray,
		SNInstanceOf,
		SNMethodCall,
		SNVariableName,
		SNBracketedExpression,
		Value,
		NullNode
	};
	struct NodeInfo {
		Semantics nodeType;
		SemanticNode *node;
		std::string name;
	};
	/** Flattened syntax tree. */
	SyntaxTreeNode *flatSyntaxNode;
	std::vector<AtomicStatement> statements;
	/** Connects the actual syntax structure value nodes with flattened syntax structure value nodes. */
	std::map<const SyntaxTreeNode *, SyntaxTreeNode *> connector;
	/** Connects value nodes on the flat syntax structure with semantic value nodes. */
	std::map<SyntaxTreeNode *, NodeInfo *> equivalentNode;

	void flattenExcessProductions(SyntaxTreeNode *expressionNode);
	int	removeExcessNodes(SyntaxTreeNode *expressionNode, SyntaxTreeNode *parentNode, int index);
	void removeEpsilonProductions(SyntaxTreeNode *expressionNode);
 int flattenExpression(SyntaxTreeNode *expressionNode, int uniqueVarIndex);

	bool canWorkWith(SyntaxTreeNode *expressionNode);
	AtomicStatement::Action parseNodes(SyntaxTreeNode *expressionNode);
	void connect(const SyntaxTreeNode *expressionNode, SyntaxTreeNode *flatExpressionNode);
	void mergeTablesWith(SemanticNodeExpression *node, SyntaxTreeNode *myRef);

	void addValue(SemanticNode *node, const SyntaxTreeNode *reference, Semantics type);

	friend SyntaxTreeNode *copyNode(const SyntaxTreeNode *aNode, SyntaxTreeNode *parent = NULL);
	friend bool isValueNode(const SyntaxTreeNode *expressionNode);

public:
	SemanticNodeExpression(const SyntaxTreeNode *expressionNode, SemanticNode *parent);
	void makeFlat();

	void addValue(SemanticNodeInstanceOf *node, const SyntaxTreeNode *reference);
	void addValue(SemanticNodeMethodCall *node, const SyntaxTreeNode *reference);
	void addValue(SemanticNodeCreateArray *node, const SyntaxTreeNode *reference);
	void addValue(SemanticNodeConstructObject *node, const SyntaxTreeNode *reference);
	void addValue(SemanticNodeCast *node, const SyntaxTreeNode *reference);
	void addValue(SemanticNodeVariableName *node, const SyntaxTreeNode *reference);
	void addValue(SemanticNodeExpression *node, const SyntaxTreeNode *reference);
	void addValue(const SyntaxTreeNode *node);

	virtual std::string toDebugString(int tab);
	// temporary
	std::string convDebug(int tab, SyntaxTreeNode *node);
};

#endif /* SEMANTICNODEEXPRESSION_H_ */
